// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "bootfs-loader-service.h"

#include <zircon/boot/bootfs.h>

namespace bootsvc {

const loader_service_ops_t BootfsLoaderService::kOps_ = {
    .load_object = BootfsLoaderService::LoadObject,
    .load_abspath = BootfsLoaderService::LoadAbspath,
    .publish_data_sink = BootfsLoaderService::PublishDataSink,
    .finalizer = nullptr,
};

zx_status_t BootfsLoaderService::LoadObject(const char* name, zx::vmo* vmo_out) {
  char tmp[ZBI_BOOTFS_MAX_NAME_LEN];
  if (snprintf(tmp, sizeof(tmp), "lib/%s", name) >= static_cast<int>(sizeof(tmp))) {
    return ZX_ERR_BAD_PATH;
  }
  uint64_t size;
  return bootfs_->Open(tmp, vmo_out, &size);
}

zx_status_t BootfsLoaderService::LoadAbspath(const char* name, zx::vmo* vmo) {
  return ZX_ERR_NOT_SUPPORTED;
}

zx_status_t BootfsLoaderService::PublishDataSink(const char* name, zx::vmo vmo) {
  return ZX_ERR_NOT_SUPPORTED;
}

BootfsLoaderService::BootfsLoaderService(fbl::RefPtr<BootfsService> svc)
    : bootfs_(std::move(svc)) {}

zx_status_t BootfsLoaderService::Create(fbl::RefPtr<BootfsService> svc,
                                        async_dispatcher_t* dispatcher,
                                        fbl::RefPtr<BootfsLoaderService>* loader_out) {
  auto ldsvc = fbl::AdoptRef(new BootfsLoaderService(svc));
  // loader_service_create points to ldsvc, so we must cal
  // loader_service_release before dropping out reference to it.
  zx_status_t status = loader_service_create(dispatcher, &kOps_, ldsvc.get(), &ldsvc->loader_);
  if (status != ZX_OK) {
    return status;
  }
  *loader_out = std::move(ldsvc);
  return ZX_OK;
}

BootfsLoaderService::~BootfsLoaderService() {
  if (loader_) {
    loader_service_release(loader_);
  }
}

zx_status_t BootfsLoaderService::Connect(zx::channel* out) {
  return loader_service_connect(loader_, out->reset_and_get_address());
}

}  // namespace bootsvc
